"""
Description  : 工具类
Author       : Senkita
Date         : 2022-09-19 11:43:14
LastEditTime : 2022-09-19 11:48:13
LastEditors  : Senkita
"""
from pathlib import Path
from typing import Union
from zipfile import ZipFile, is_zipfile

from configs.log_conf import log_dir
from loguru import logger
from py7zr import SevenZipFile, is_7zfile
from unrar.rarfile import RarFile, is_rarfile

from src.db.models import Pwd


def compress_7z(parent_dir: Path, subfile: Path) -> list[Path]:
    """
    description: 解压7zip文件
    param       {Path} parent_dir - 上层目录
    param       {Path} subfile - 文件路径
    return      {*}
    author     : Senkita
    """
    subfile_path: str = subfile.as_posix()
    with SevenZipFile(subfile_path) as f:
        extract_path: Path = Path(parent_dir, subfile.stem)
        extract_path.mkdir(parents=True, exist_ok=True)

        f.extractall(extract_path)
    subfile.unlink()
    return [extract_path]


def is_compress_file(parent_dir: Path, subfile: Path) -> Union[list[Path], None]:
    """
    description: 判断是否压缩文件，是即解压
    param       {Path} parent_dir - 上级目录
    param       {Path} subfile - 文件路径
    return      {list[Path]} compress_subfile_dir_list - 解压出来的子文件所在目录
    author     : Senkita
    """
    subfile_path: str = subfile.as_posix()
    compress_subfile_dir_list: list[Path] = []

    if is_zipfile(subfile_path):
        compress_file: ZipFile = ZipFile(subfile_path)
    elif is_rarfile(subfile_path):
        compress_file: RarFile = RarFile(subfile_path)
    elif is_7zfile(subfile_path):
        return compress_7z(parent_dir, subfile)
    else:
        return None

    for compress_subfile in compress_file.namelist():
        try:
            current_path: Path = Path(
                parent_dir, compress_subfile.encode("cp437").decode("gbk")
            )
        # 遇到没有乱码的文件名
        except UnicodeError:
            current_path = Path(
                parent_dir, compress_subfile.encode("utf-8").decode("utf-8")
            )

        Path(Path.cwd(), current_path.parent).mkdir(parents=True, exist_ok=True)

        extract_path: Path = Path(compress_file.extract(compress_subfile))
        try:
            extract_path.rename(current_path)
        except OSError:
            pass

        if current_path.is_dir():
            compress_subfile_dir_list.append(current_path)
        else:
            compress_subfile_dir_list.append(current_path.parent)

        try:
            extract_path.parent.rmdir()
        except OSError:
            pass

    subfile.unlink()

    return list(set(compress_subfile_dir_list))


def is_txt(subfile: Path) -> bool:
    """
    description: 判断是不是txt文件
    param       {Path} subfile - 文件路径
    return      {bool}
    author     : Senkita
    """
    if subfile.suffix.lower() == ".txt":
        return txt2db(subfile)
    return False


txt2db_logger = logger
txt2db_log_file: Path = Path(log_dir, "txt2db_{time}.log")

txt2db_logger.add(
    txt2db_log_file,
    rotation="100 MB",
    retention="1 week",
    compression="zip",
    format="{time:YYYY-MM-DD at HH:mm:ss} - {level} - {message}",
    filter=lambda x: "[txt2db]" in x["message"],
    level="INFO",
    enqueue=True,
    encoding="utf-8",
)


def txt2db(subfile: Path) -> bool:
    """
    description: txt文件录入数据库
    param       {Path} subfile - 文件路径
    return      {bool}
    author     : Senkita
    """
    subfile_path: str = subfile.as_posix()
    row_num: int = 1

    with open(subfile_path, "r") as f:
        try:
            nextline: str = f.readline().strip("\n")
        except UnicodeDecodeError:
            txt2db_logger.error("[txt2db] {}无法正常读入。".format(subfile))
            subfile.unlink()
            return True

        while nextline:
            if len(nextline) >= 8 and len(nextline) <= 64:
                Pwd.insert(subfile=subfile, password=nextline)

            row_num += 1

            try:
                nextline = f.readline().strip("\n")
            except UnicodeDecodeError:
                txt2db_logger.error("[txt2db] {}第{}行无法正常读入。".format(subfile, row_num))

    subfile.unlink()
    return True


traverse_logger = logger
traverse_log_file: Path = Path(log_dir, "traverse_{time}.log")

traverse_logger.add(
    traverse_log_file,
    rotation="100 MB",
    retention="1 week",
    compression="zip",
    format="{time:YYYY-MM-DD at HH:mm:ss} - {level} - {message}",
    filter=lambda x: "[traverse]" in x["message"],
    level="INFO",
    enqueue=True,
    encoding="utf-8",
)


def traverse(parent_dir: Path) -> list[Path]:
    """
    description: 遍历文件夹
    param       {Path} parent_dir - 文件夹路径
    return      {*}
    author     : Senkita
    """
    dir_list: list[Path] = []
    for subfile in parent_dir.iterdir():
        if subfile.is_dir():
            try:
                subfile.rmdir()
            except OSError:
                dir_list.append(subfile)
        else:
            txt_result: bool = is_txt(subfile)
            if not txt_result:
                compress_result: Union[list[Path], None] = is_compress_file(
                    parent_dir, subfile
                )
                if compress_result is not None:
                    dir_list.extend(compress_result)
                else:
                    traverse_logger.warning(
                        "[traverse] 快去看看{}，它好像啥也不是。".format(subfile)
                    )
                    subfile.unlink()
    return list(set(dir_list))
